/*SCBFileEditor
filename:   main.cpp
date:       April 2010
author:     Jeffrey Geyssens
about:      This file contains implementation of the SCBFileEditor.
            It can be invoked on it's own, auto-detected by UniApoFileEditor
            or using the ui
            
 */


#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "../UniApoLib/SCBFile.h"

using namespace std;

int main(int argc, char **argv) {
    if (argc != 3) {
        cerr << "ERROR (SCB File Editor): Requires two arguments" << endl;
        return 1;
    }
    void processLine(string const & lineData);
    string option = argv[1];
    string file = argv[2];
    string filename = file.substr(0, file.size() - 4);
    string extension = file.substr(file.size() - 4, file.size());

    //First we check if a correct filename was supplied
    if (extension != ".SCB") {
        cerr << cerr << "ERROR in extension (SCB File Editor): Expected filename.SCB extension" << endl;
        return 3;
    }
    //Next we check if the option format supplied is correct
    //If the size of the argument (which must be 2) is incorrect
    //or the argument does not start with '-'
    if ((option.size() != 2) || (option.at(0) != '-')) {
        cerr << "ERROR in 1st argument (SCB File Editor): Use -n for new file, -o for open existing file or -d to delete a file." << endl;
        return 2;
    }
    //Then we check if the first character of the option is -

    //Next we get the fullpath of the object given (location /Saves/SCB/
    char coption = option.at(1);


    //We create the SCBFile object to be used..
    SCBFile openSCB;
    openSCB.name(filename);
    switch (coption) {
        case 'n':
        { //Creation of a new file
            //Store in UniApo/Saves/SCB
            
            openSCB.buildFile();
            cout << "New File Created" << endl;
            coption = 'o'; //Now open the new file

        }

        case 'o':
        {
            cout << "Open Existing File" << endl;

            openSCB.loadFile();
            cout << "File opened (showing contents)" << endl;
            openSCB.print();

            string mod;
            string smod;
            string pmod;
            string symbol;
            string definition;
            string mask;
            string drt;
            string NT;
            string derivation;

            //SCBEditor (choice of SymDef editor or PRule Editor)
            while (mod != "q") {
                cout << "Enter command (d,p,q,s or h for help): ";
                getline(cin, mod);
                if (mod == "h") {
                    cout << "---SCBEditor Help---" << endl;
                    cout << "Type d to edit symbol definitions" << endl;
                    cout << "Type p to edit production rules" << endl;
                }

                if (mod == "d") {
                    cout << "Symbol Definition Editor" << endl;
                    while (smod != "q") {
                        //clear screen?
                        openSCB.printSymDef();
                        cout << "Enter command (a,m,d,b,q,s or h for help): ";
                        getline(cin, smod);
                        if (smod == "s") {
                            cout << "saving" << openSCB.getPath()<< endl;
                            openSCB.buildFile();
                            cout << "file saved" << endl;
                        }
                        if (smod == "h") {
                            cout << "**********Symbol Definition (SD) Editor Help************* " << endl;
                            cout << "In this section we store an unsorted list of symbols, together with their definitions." << endl;
                            cout << "Once mapped to a DBS file, SD data serves as the main lookup data when parsing datastrings" << endl;
                            cout << "You can add, modify and delete SD entries" << endl;
                            cout << "SD entries are 4-tupples, (s,d,m,drt)" << endl;
                            cout << "s: Symbol: Some symbol or abbriviation used in a datastring." << endl;
                            cout << "d: Definition: The meaning of the symbol, in human language" << endl;
                            cout << "drt: Data Reference Terminal. The context of the symbol" << endl;
                            cout << "Example: (J,Jeffrey,,Person)" << endl;
                            cout << "         (H,Hayat,,Person)" << endl;
                            cout << "         (H,Herbie,,Car)" << endl;
                            cout << "Person and Car represent two different contexts, which are (usually) stored in two seperate tables " << endl;
                            cout << "m: Mask: The representation of symbol is stored differently as in the database  " << endl;
                            cout << "Example: (J,Jeffrey,JE,Person)" << endl;
                            cout << "This means that somewhere in a database exists a table related to a context Person" << endl;
                            cout << "An entry having two distinct attributes holds values J and Jeffrey." << endl;
                            cout << "When parsing a datastring it will not scan for J, but rather for JE" << endl;
                            cout << "When converting for storage it will correct the values to correspond with the values in the database" << endl;
                            cout << "It is particularly useful with parsing rules that use modifiers" << endl;
                            cout << "It can also be used to mix or translate languages" << endl;
                            cout << "You can also add SCB entries in bulk" << endl;
                            cout << "For this you need CSV file of the following format:" << endl;
                            cout << "symbol, definition, mask, drt" << endl;

                        }
                        if (smod == "b") {
                            cout << "Adding SD entries in bulk" << endl;
                            cout << "Enter full path of csv file: ";
                            string path;
                            getline(cin, path);
                            openSCB.bulkSymDef(path);
                            openSCB.printSymDef();
                        }
                        if (smod == "a") {
                            cout << "Enter Symbol: ";
                            getline(cin, symbol);
                            cout << "Enter Definition: ";
                            getline(cin, definition);
                            cout << "Enter Mask: ";
                            getline(cin, mask);
                            cout << "Enter Data Reference terminal: ";
                            getline(cin, drt);

                            if ((symbol == "") || (definition == "")) {
                                cerr << "Entering Symbol and Definition is mandatory" << endl;
                            }

                            openSCB.addSymDef(symbol, definition, mask, drt);
                            openSCB.printSymDef();
                        }
                        if (smod == "m") {

                            cout << "Leaving fields blank leaves old values intact" << endl;
                            int entryNo;
                            string xline;
                            cout << "Enter entry number: ";
                            getline(cin, xline);

                            stringstream ss(xline);
                            ss >> entryNo;

                            cout << "Enter Symbol: ";
                            getline(cin, symbol);
                            cout << "Enter Definition: ";
                            getline(cin, definition);
                            cout << "Enter Mask: ";
                            getline(cin, mask);
                            cout << "Enter Data Reference terminal: ";
                            getline(cin, drt);

                            openSCB.modifySymDef
                            (entryNo, symbol, definition, mask, drt);
                            openSCB.printSymDef();
                        }
                        if (smod == "d") {
                            int entryNo;
                            string xline;
                            cout << "Enter entry number: ";
                            getline(cin, xline);
                            stringstream ss(xline);
                            ss >> entryNo;
                            openSCB.removeSymDef(entryNo);
                        }
                    }
                }

                if (mod == "p") {
                    cout << "Production Rule Editor" << endl;
                    while (pmod != "q") {
                        //clear screen?
                        openSCB.printPRule();

                        cout << "Enter Command (a,b,d,q,s or h for help): ";
                        getline(cin, pmod);
                        if (pmod == "a") {
                            cout << "Enter Generating Non Terminal: ";
                            getline(cin, NT);
                            cout << "Enter Generated Derivation: ";
                            getline(cin, derivation);

                            if ((NT == "") || (derivation == "")) {
                                cerr << "Non Terminal or Derivation can not be left blank" << endl;
                            }
                            openSCB.addPRule(NT, derivation);

                        }
                        if (pmod == "b") {
                            cout << "Adding PR entries in bulk" << endl;
                            cout << "Enter full path of csv file: ";
                            string path;
                            getline(cin, path);
                            openSCB.bulkPRule(path);
                            openSCB.printPRule();
                            
                        }

                        if (pmod == "d") {
                            cout << "Enter Non Terminal to delete: ";
                            getline(cin, NT);
                            openSCB.printPRule(NT);

                            if (openSCB.count(NT) == 1) {
                                openSCB.removePRule(NT, 1);
                            } else {

                                cout << "Which production do you want to delete: ";
                                int entryNo;
                                string xline;
                                getline(cin, xline);
                                stringstream ss(xline);
                                ss >> entryNo;
                                openSCB.removePRule(NT, entryNo);
                            }
                        }
                        if (pmod == "s") {
                            cout << "saving: " << openSCB.getPath() << endl;
                            openSCB.buildFile();
                            cout << "file saved" << endl;
                        }

                        if (pmod == "h") {
                            cout << "**********Production Rule (PR) Editor Help************* " << endl;
                            cout << "In this section we store an list of production rules, sorted by generating Non Terminal" << endl;
                            cout << "You can add and delete PR to the list using this module" << endl;
                            cout << "PR entries are of type: NT    ::==    DerivationString" << endl;


                        }
                    }
                }


                if (mod == "s") {
                    cout << "saving" << endl;
                    openSCB.buildFile();
                    cout << "file saved" << openSCB.getPath() << endl;

                }

            }


        }
            break;

        case 'd':
        {
            //are you sure?
            string confirm;
            while ((confirm != "y") || (confirm != "n")) {
                cout << "Are you sure?(y/n): " << endl;
                getline(cin, confirm);
                if (confirm == "n") {
                    return 0;
                }
                if (confirm == "y") {
                    if (remove(openSCB.getPath().c_str()) != 0) {
                        cerr << "ERROR (SCB File Editor): No such file" << endl;
                        return 4;
                    } else
                        cout << "File deleted" << endl;
                    break;
                }
            }
        }
            break;

        default:
        {
            cerr << "ERROR (SCB File Editor): 1st argument must be ";
            cerr << "-n for new file, -o for open existing file ";
            cerr << "or -d to delete a file" << endl;
            return 2;
        }
            break;
    }
    return 0;
}
